#include <functional>
#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <memory>
template <class... Args> void print(const Args &...args)
{
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}
class Single
{
public:
    Single(const Single &) = delete;
    Single &operator=(const Single &) = delete;
    static Single *getInstance()
    {
        if (sing == nullptr)
        {
            sing = new Single();
        }
        return sing;
    }

private:
    Single() = default;
    static Single *sing;
};

Single *Single::sing = nullptr;
void func1()
{
    print("func Single address");
    print(Single::getInstance());
}

class Single1
{
private:
    static Single1 *sing1;
    static std::mutex lock;
    Single1() = default;

public:
    Single1(const Single1 &) = delete;
    Single1 &operator=(const Single1 &) = delete;

    static Single1 *getInstance1()
    {
        if (sing1 != nullptr)
        {
            return sing1;
        }
        lock.lock();
        sing1 = new Single1();
        lock.unlock();
        return sing1;
    }
};
void func2()
{
    print("func Single address");
    print(Single::getInstance());
}
Single1 *Single1::sing1 = nullptr;

// 懒汉单例
class Single3
{
    Single3() { print("world"); }

public:
    Single3(const Single3 &) = delete;
    Single3 &operator=(const Single3 &) = delete;
    static Single3 &getInstancesing3()
    {
        static Single3 s;
        return s;
    }
};
// 饿汉单例
class Single4
{
public:
    static Single4 &getInstancesing4() { return sin; }

private:
    Single4() { print("hello"); }
    Single4(const Single4 &) = delete;
    Single4 &operator=(const Single4 &) = delete;
    static Single4 sin;
};
Single4 Single4::sin;

void func3() { print(&Single3::getInstancesing3()); }
class SingleAuto;
class SafeDeletor
{
public:
    void operator()(SingleAuto *ptr) const
    {
        print("specifier deletor");
        delete ptr;
    }
};
class SingleAuto
{
    SingleAuto() {}
    friend class SafeDeletor;
    SingleAuto(const SingleAuto &) = delete;
    SingleAuto &operator=(const SingleAuto &) = delete;

    ~SingleAuto() { print("single auto delete success"); }

public:
    static std::shared_ptr<SingleAuto> getInst()
    {
        if (single != nullptr)
        {
            return single;
        }
        _mutex.lock();
        // 使用双重检查锁定DCLP在多线程环境中保证单例模式的安全创建,并减少锁的使用开销
        if (single != nullptr)
        {
            _mutex.unlock();
            return single;
        }
        single.reset(new SingleAuto(), SafeDeletor());
        _mutex.unlock();
        return single;
    }

private:
    static std::mutex _mutex;
    static std::shared_ptr<SingleAuto> single;
};
std::mutex SingleAuto::_mutex;
std::shared_ptr<SingleAuto> SingleAuto::single = nullptr;

void test()
{
    auto sp1 = SingleAuto::getInst();
    auto sp2 = SingleAuto::getInst();
    print("sp1 is ", sp1);
    print("sp2 is ", sp2);
    // 为特定资源定制删除器
}

template <typename T> class SingletonOnce
{
protected:
    SingletonOnce() = default;
    SingletonOnce(const SingletonOnce<T> &) = delete;
    SingletonOnce &operator=(const SingletonOnce<T> &st) = delete;
    static std::shared_ptr<T> _instance;

public:
    static std::shared_ptr<T> getInsta()
    {
        static std::once_flag s_flag;
        std::call_once(s_flag,
                       [&]() { _instance = std::shared_ptr<T>(new T); });
        return _instance;
    }
    void PrintAddress() { std::cout << _instance.get() << std::endl; }
    ~SingletonOnce() { std::cout << "this is singleton destruct" << std::endl; }
};
template <typename T> std::shared_ptr<T> SingletonOnce<T>::_instance = nullptr;

class t : public SingletonOnce<t>
{
    friend class SingletonOnce<t>;

public:
};
void TestSingle()
{
    std::thread t1([]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        SingletonOnce<t>::getInsta()->PrintAddress();
    });
    std::thread t2([]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        SingletonOnce<t>::getInsta()->PrintAddress();
    });
    t1.join();
    t2.join();
}
int main()
{
    // print(&Single3::getInstancesing3());
    // print(&Single4::getInstancesing4());
    // std::thread t([]() {
    //     print("thread t Single address");
    //     print(Single::getInstance());
    // });
    // t.join();
    // func1();
    // func2();
    // func3();
    // test();
    TestSingle();
    return 0;
}
